/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.actions;
import javax.swing.*;
import javax.swing.event.*;
import org.openide.awt.JInlineMenu;
import org.openide.util.NbBundle;
import org.openide.util.HelpCtx;
import org.openide.util.WeakListener;
import org.openide.util.actions.*;
/** A "meta-action" that displays (in a submenu) a list of enabled actions provided by modules.
* Such registered actions are called "service actions":
* they are provided externally but seem to provide additional services on existing components.
* Often they will be {@link NodeAction}s or {@link CookieAction}s so that they will
* be enabled based on the node selection, i.e. the node containing this popup.
* It is desirable for most nodes to include this action somewhere in their popup menu.
*
* <p><em>Note:</em> you do not need to touch this class to add a service action!
* Just add the action to a module manifest in an <code>Action</code> section.
*
* <p>The list of registered service actions is provided to this action from the implementation
* by means of {@link ToolsAction.Model}.
*
* @author Jaroslav Tulach
*/
public class ToolsAction extends SystemAction
implements Presenter.Menu, Presenter.Popup {
static final long serialVersionUID =4906417339959070129L;
/** the model to use for this action */
static Model model; // package private because used in Menu subclass
/* @return name
*/
public String getName () {
return getActionName ();
}
/* @return help for this action
*/
public HelpCtx getHelpCtx () {
return new HelpCtx (ToolsAction.class);
}
/* @return menu presenter for the action
*/
public JMenuItem getMenuPresenter () {
return createMenu (true);
}
/* @return menu presenter for the action
*/
public JMenuItem getPopupPresenter () {
return createMenu (false);
}
/* Does nothing.
*/
public void actionPerformed (java.awt.event.ActionEvent ev) {
}
/** Assigns a model which can provide a list of service actions.
* This can be done only once.
* @param m a model that provides all actions installed by modules
* @exception SecurityException if a model is already present
*/
public synchronized static void setModel (Model m) {
if (model != null) throw new SecurityException ();
model = m;
}
/* @return name
*/
private static String getActionName () {
return ActionConstants.BUNDLE.getString ("CTL_Tools");
}
/* Creates the menu.
*/
private static JMenuItem createMenu (boolean menu) {
return new Inline (menu);
}
/** A model that provides a list of all service actions.
* Normally these will be all actions installed by modules via their manifests.
*/
public static interface Model {
/** Get all registered actions.
* Can contain <code>null</code>s that will be replaced by separators.
*/
public SystemAction[] getActions ();
/** Add a change listener to listen on changes of the set of actions.
* @param l the listener to add
*/
public void addChangeListener (javax.swing.event.ChangeListener l);
/** Remove a change listener.
* @param l the listener to remove
*/
public void removeChangeListener (javax.swing.event.ChangeListener l);
}
/** Inline menu. That is registered to changes of model.
*/
private static final class Inline extends JInlineMenu {
/** sub menu */
private Menu menu;
static final long serialVersionUID =2269006599727576059L;
public Inline (boolean isForMenu) {
this.menu = new Menu (this, isForMenu);
if (isForMenu) this.menu.setIcon (SystemAction.get (ToolsAction.class).getIcon ());
}
void update () {
if (menu.getMenuComponentCount () > 0) {
setMenuItems (new JMenuItem[] { menu });
} else {
setMenuItems (new JMenuItem[0]);
}
}
}
/** Menu that displayes all activated actions.
*/
private static final class Menu extends org.openide.awt.JMenuPlus implements ChangeListener {
/** true if generation for menu, false otherwise */
private boolean menu;
/** reference to inline menu */
private Inline il;
/** true if the actions should be regenerated */
private boolean dirty;
static final long serialVersionUID =4339180785531920683L;
/** @param menu true if generating for menu */
Menu (Inline il, boolean menu) {
super (getActionName ());
this.menu = menu;
this.il = il;
HelpCtx.setHelpIDString (this, ToolsAction.class.getName ());
generate ();
ToolsAction.model.addChangeListener (WeakListener.change (this, ToolsAction.model));
}
/** Click does nothing.
*/
public void doClick (int ms) {
// ignore
}
/** Change of model.
*/
public void stateChanged (ChangeEvent ev) {
generate ();
}
/** Generate menu.
*/
private void generate () {
dirty = true;
SwingUtilities.invokeLater (new Runnable () {
public void run () {
if (!dirty) {
// ok, return
return;
}
// mark not dirty and continue
dirty = false;
removeAll ();
SystemAction[] actions = ToolsAction.model.getActions ();
boolean separator = false;
boolean firstItemAdded = false; // flag to prevent adding separator before actual menu items
for (int i = 0; i < actions.length; i++) {
SystemAction a = actions[i];
if (a == null) {
if (firstItemAdded) separator = true;
continue;
}
// not null
if (a.isEnabled ()) {
// only enabled actions
if (menu && a instanceof Presenter.Menu) {
if (separator) {
addSeparator ();
separator = false;
}
add (((Presenter.Menu)a).getMenuPresenter ());
firstItemAdded = true;
continue;
}
// popup
if (!menu && a instanceof Presenter.Popup) {
if (separator) {
addSeparator ();
separator = false;
}
add (((Presenter.Popup)a).getPopupPresenter ());
firstItemAdded = true;
continue;
}
}
}
il.update ();
}
});
}
} // end of Menu
}
/*
* Log
* 20 Gandalf 1.19 2/6/00 Jaroslav Tulach Should survive clicking
* on it.
* 19 Gandalf 1.18 12/21/99 Ian Formanek Fixed last change
* 18 Gandalf 1.17 12/20/99 Ian Formanek Fixed icon in menu
* 17 Gandalf 1.16 11/5/99 Jaroslav Tulach WeakListener has now
* registration methods.
* 16 Gandalf 1.15 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 15 Gandalf 1.14 8/17/99 Ian Formanek Generated serial version
* UID
* 14 Gandalf 1.13 8/17/99 Jaroslav Tulach Does not regenerate the
* state so often.
* 13 Gandalf 1.12 8/17/99 Jaroslav Tulach Appears again.
* 12 Gandalf 1.11 8/16/99 Jaroslav Tulach Deadlock solved.
* 11 Gandalf 1.10 8/9/99 Ian Formanek Generated Serial Version
* UID
* 10 Gandalf 1.9 8/5/99 Jaroslav Tulach Tools & New action in
* editor.
* 9 Gandalf 1.8 7/19/99 Ian Formanek Preventing adding
* separator as the first item
* 8 Gandalf 1.7 7/19/99 Jesse Glick Context help.
* 7 Gandalf 1.6 6/28/99 Ian Formanek NbJMenu renamed to
* JMenuPlus
* 6 Gandalf 1.5 6/28/99 Ian Formanek Fixed bug 2043 - It is
* virtually impossible to choose lower items of New From Template from
* popup menu on 1024x768
* 5 Gandalf 1.4 6/24/99 Jesse Glick Gosh-honest HelpID's.
* 4 Gandalf 1.3 6/10/99 Jesse Glick [JavaDoc]
* 3 Gandalf 1.2 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 2 Gandalf 1.1 5/13/99 Ian Formanek Services -> Tools
* 1 Gandalf 1.0 5/13/99 Jaroslav Tulach
* $
*/